﻿using System;

using System.Collections.Generic;
using System.Text;
using Silvermoon.Shapes;
using System.Drawing;
using Silvermoon.Interfaces;
using Silvermoon.UI;

namespace Silvermoon.Controls
{
    /// <summary>
    /// Abstract base control with Background property.
    /// </summary>
    public abstract class ChromeControl : Control, IColor
    {
        #region fields

        /// <summary>
        /// direct access to background storage for inherited controls.
        /// </summary>
        private Shape background;
        internal Shape chrome;
        private Color color, chromeColor;

        #endregion
        #region ctors


        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected override void Dispose(bool dispose)
        {
            DisposeObject(background);
            DisposeObject(chrome);
            background = null;
            chrome = null;
            base.Dispose(dispose);
        }


        #endregion
        #region accessors

        public static PropertyAccessor<ChromeControl, Color> ChromeColorProperty = PropertyAccessor.Register<ChromeControl, Color>(
            "ChromeColor",
            c => c.ChromeColor,
            (c, v) => c.ChromeColor = v);

        public static PropertyAccessor<ChromeControl, int> ChromeOpacityProperty = PropertyAccessor.Register<ChromeControl, int>(
            "ChromeOpacity",
            c => c.ChromeOpacity,
            (c, v) => c.ChromeOpacity = v);


        public static PropertyAccessor<ChromeControl, int> BackgroundOpacityProperty = PropertyAccessor.Register<ChromeControl, int>(
            "BackgroundOpacity", c => c.BackgroundOpacity, (c, v) => c.BackgroundOpacity = v);

        #endregion
        #region props

        /// <summary>
        /// Gets or sets the opacity of the background.
        /// </summary>
        public int BackgroundOpacity
        {
            get
            {
                return background != null ? background.Opacity : 0;
            }
            set
            {
                if (BackgroundOpacity != value)
                {
                    if (background != null)
                    {
                        background.Opacity = value;
                        Invalidate(InvalidationFlag.Appearance);
                    }
                }
            }
        }

        protected Rectangle ChromeRect
        {
            get { return GetChromeRect(); }
        }

        public Color ChromeColor
        {
            get { return chromeColor; }
            set
            {
                if (chromeColor != value)
                {
                    chromeColor = value;
                    Shape chrome = Chrome;
                    if (chrome != null) chrome.Color = value;
                    OnChromeColorChanged();
                }
            }
        }

        public int ChromeOpacity
        {
            get
            {
                Shape chrome = Chrome;
                return chrome != null ? chrome.Opacity : 255;
            }
            set
            {
                Shape chrome = Chrome;
                if (chrome != null && chrome.Opacity != value)
                {
                    chrome.Opacity = value;
                    OnChromeOpacityChanged();
                }
            }
        }

        public Shape Chrome
        {
            get { return chrome; }
            set
            {
                if (chrome != value)
                {
                    chrome = value;
                    OnChromeChanged();
                }
            }
        }


        /// <summary>
        /// Gets or sets the background shape.
        /// </summary>
        public Shape Background
        {
            get { return background; }
            set
            {
                if (background != value)
                {
                    if (background != null)
                    {
                        Shapes.Remove(background);
                        background.Dispose();
                    }
                    ControlFlags &= ~ControlFlags.Background;
                    background = value;
                    if (background != null) Shapes.AddFirst(background);
                    OnBackgroundChanged();
                }
            }
        }

        /// <summary>
        /// Gets the bounds for the background shape.
        /// </summary>
        protected virtual Rectangle BackgroundRect
        {
            get
            {
                return Control.ScaledRect(0, 0, Width, Height);
            }
        }

        /// <summary>
        /// Gets or sets the color of the background, if a background shape is set.
        /// </summary>
        public override Color Color
        {
            get { return color; }
            set
            {
                if (color != value)
                {
                    color = value;
                    Shape bg = Background;
                    if (bg != null) bg.Color = value;
                    OnColorChanged();
                }
            }
        }

        #endregion
        #region methods

        protected Color GetParentColor()
        {
            Control p = Parent;
            while (p != null && p.Color.IsEmpty) p = p.Parent;
            return p != null ? p.Color : Color.Empty;
        }


        protected virtual void OnChromeChanged()
        {
            Invalidate(InvalidationFlag.LayoutAppearance);
        }

        protected virtual Shape CreateDefaultChrome()
        {
            return null;
        }

        protected virtual void OnChromeColorChanged()
        {
            Invalidate(InvalidationFlag.Appearance);
        }

        protected virtual void OnChromeOpacityChanged()
        {
            Invalidate(InvalidationFlag.Appearance);
        }

        protected override void ApplyStyle()
        {
            base.ApplyStyle();
            if (background == null) Background = CreateDefaultBackground();
            if (chrome == null) chrome = CreateDefaultChrome();
            if (background != null && !color.IsEmpty) background.Color = color;
            if (chrome != null && !chromeColor.IsEmpty) chrome.Color = chromeColor;
        }

        protected override void PreLayout()
        {
            Shape chrome = Chrome;
            if (chrome != null) chrome.PreLoad();
            base.PreLayout();
        }


        /// <summary>
        /// Occurs when the color property has changed.
        /// </summary>
        protected virtual void OnColorChanged()
        {
            Invalidate(InvalidationFlag.Color);
        }

        /// <summary>
        /// Occurs when to layout all shapes and child controls.
        /// </summary>
        protected override void OnLayout()
        {
            if (CheckFlag(InvalidationFlag.Layout | InvalidationFlag.Size))
            {
                if (Background != null) background.Bounds = BackgroundRect;
                if (Chrome != null) chrome.Bounds = GetChromeRect();
            }
            base.OnLayout();
        }

        /// <summary>
        /// Occurs when the background has changed.
        /// </summary>
        protected virtual void OnBackgroundChanged()
        {
            Invalidate(InvalidationFlag.LayoutAppearance);
        }

        /// <summary>
        /// Creates the default shape if none is specified.
        /// </summary>
        /// <returns></returns>
        protected virtual Shape CreateDefaultBackground()
        {
            return null;
        }

        protected virtual Rectangle GetChromeRect()
        {
            return BackgroundRect;
        }

        protected internal override void OnRender(Silvermoon.Core.Renderer renderer)
        {
            ShapeCollection shapes = this.Shapes;
            if (chrome != null)
            {
                Rectangle scissorBox = renderer.ScissorBox;
                int alpha = renderer.Alpha;
                if (shapes != null) renderer.RenderShapes(shapes);
                renderer.ScissorBox = scissorBox;
                renderer.RenderShape(chrome, alpha);
            }
            else
            {
                if (shapes != null) renderer.RenderShapes(shapes);
            }
        }

        #endregion

    }
}
